package com.smzd.framework.sso;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;

import com.smzd.framework.sso.domain.SocialUser;
import com.smzd.framework.utils.URIStacks;
import com.smzd.utils.SessionHolder;

public abstract class OAuth2AuthenticationProcessor {
    protected String state;
    protected int platform;
    
    protected String root = null;
    
    private FriendDetecter friendDetecter;

    protected OAuth2AuthenticationProcessor() {

    }

    protected OAuth2AuthenticationProcessor(String state) {
        this.state = state;
    }

    public boolean support(String state) {
        if (state == null || this.state == null) {
            return false;
        }
        return state.equalsIgnoreCase(this.state);
    }
    
    public SocialUser getSocialUser(String queryString, HttpServletRequest request) throws Exception{
        Object accessToken = getAccessToken(queryString);
        Object remoteUserInfo = getRemoteUserInfo(accessToken);
        SocialUser socialUser = convertRemoteToSocialUser(remoteUserInfo);
        HttpSession session = request.getSession();
        session.setAttribute("OBJECT_ACCESS_TOKEN", accessToken);
        SessionHolder.setObject("OBJECT_ACCESS_TOKEN", accessToken);
        return socialUser;
    }
    
    public URIStacks initURIStacks(HttpServletRequest request) throws Exception {
        URIStacks stacks = retrieveURIStacks(request);
        if (stacks == null) {
            stacks = URIStacks.getInstance();
            restoreToSession(request, stacks);
        }
        stacks.clear();
        return stacks;
    }

    protected void restoreToSession(HttpServletRequest request, URIStacks stacks) {
        HttpSession session = request.getSession();
        session.setAttribute(URIStacks.URISTACKS_SESSION_KEY, stacks);
        SessionHolder.setObject(URIStacks.URISTACKS_SESSION_KEY, stacks);
    }

    protected URIStacks retrieveURIStacks(HttpServletRequest request) {
        URIStacks stacks = SessionHolder.getObject(URIStacks.URISTACKS_SESSION_KEY);
        if (stacks == null) {
            HttpSession session = request.getSession();
            stacks = (URIStacks) session.getAttribute(URIStacks.URISTACKS_SESSION_KEY);
        }
        return stacks;
    }

    public abstract Object getAccessToken(String queryString) throws Exception;

    public abstract Object getRemoteUserInfo(Object accessToken) throws Exception;

    public abstract SocialUser convertRemoteToSocialUser(Object remoteUserInfo) throws Exception;
    
    public abstract String getAuthenticationURL() throws Exception;
    
    public abstract List<String> getFriendOpenids(SocialUser socialUser, Object accessToken) throws Exception;

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public int getPlatform() {
        return platform;
    }

    public void setPlatform(int platform) {
        this.platform = platform;
    }

	public FriendDetecter getFriendDetecter() {
		return friendDetecter;
	}

	public void setFriendDetecter(FriendDetecter friendDetecter) {
		this.friendDetecter = friendDetecter;
	}
	
    public void downloadFile(String url, String filename)
            throws ClientProtocolException, IOException {
        HttpClient client = new DefaultHttpClient();
        HttpUriRequest request = new HttpGet(url);
        HttpResponse response = client.execute(request);
        response.getEntity().getContent();
        File storeFile = new File(root, filename);
        downloadFile(response.getEntity().getContent(), storeFile);
    }

    public static void downloadFile(InputStream is, File file)
            throws IOException {
        FileOutputStream output = new FileOutputStream(file);
        byte[] b = new byte[1024 * 4];
        int len;
        while ((len = is.read(b)) != -1) {
            output.write(b, 0, len);
        }
        output.flush();
        output.close();
    }

    public String getRoot() {
        return root;
    }

    public void setRoot(String root) {
        this.root = root;
    }
}
